package com.lanlian.volleylib;

import android.text.TextUtils;
import android.util.Log;

import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.Response.Listener;
import com.android.volley.error.VolleyError;
import com.google.gson.Gson;
import com.lanlian.volleylib.annotation.HttpReqParam;
import com.lanlian.volleylib.cache.CacheConfig;
import com.lanlian.volleylib.cache.CacheManager;
import com.lanlian.volleylib.request.GsonRequestEX;
import com.lanlian.volleylib.request.JsonObjectRequestEX;

import org.json.JSONException;
import org.json.JSONObject;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.TreeMap;

/**
 * @author pengjin
 * @version V1.0
 * @Description: Http请求代理，支持扩展域名、公共参数、加密算法
 * @date 2015-10-24 下午2:17:15
 */
public abstract class AbsHttpRequestProxy<T> {

    private static final int DEFAULT_SOCKET_TIMEOUT_MS = 30000;

    private Request request;
    protected Class<T> clazz;
    protected RequestListener<T> listener;
    protected Object requestParamBody;
    protected String protocol;
    protected HttpReqParam.HttpReqMethod method;
    protected String tag;
    protected boolean cache = false;
    protected boolean getCache = false;
    private Gson mGson = new Gson();
    protected long expireTime;

    /**
     * 域名
     */
    protected abstract String getDomain();

    /**
     * 请求头
     */
    protected abstract TreeMap<String, String> getHeader();

    /**
     * 公共参数
     */
    protected abstract TreeMap<String, String> getCommonParamMap();

    /**
     * 执行http请求
     */
    public void execute() {
        if (method == HttpReqParam.HttpReqMethod.HTTP_GET) {
            doGet();
        } else {
            doPost();
        }
    }

    /**
     * 取消请求
     */
    public void cancel() {
        request.cancel();
    }

    /**
     * get方式请求
     */
    private void doGet() {
        final String requestUrl = buildRequestUrl(protocol);
        Map<String, String> params = getRequestParams();
        if (BuildConfig.DEBUG) {
            Log.e("AbsHttpRequestProxy", "protocol = " + requestUrl);
            Log.e("AbsHttpRequestProxy", "reqParam = " + params);
        }
        request = new GsonRequestEX<>(Request.Method.GET, requestUrl, clazz, getHeader(), params, new Listener<T>() {
            @Override
            public void onResponse(T response) {
                if (response != null) {
                    if (cache) {
                        CacheConfig.methodExpireTimes.put(protocol, expireTime);
                        CacheManager.put(protocol, requestParamBody, response);
                    }
                }
                listener.onSuccess(response);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                if (BuildConfig.DEBUG) {
                    Log.e("AbsHttpRequestProxy", "error = " + error.toString());
                }
                listener.onFailed(error);
            }
        });

        addRequestQueue();
    }

    /**
     * post方式请求
     */
    private void doPost() {
        final String requestUrl = buildRequestUrl(protocol);
        try {
            String reqParam = getRequestJsonString();
            if (BuildConfig.DEBUG) {
                Log.e("AbsHttpRequestProxy", "protocol = " + requestUrl);
                Log.e("AbsHttpRequestProxy", "reqParam = " + reqParam);
            }
            request = new JsonObjectRequestEX<>(Request.Method.POST, requestUrl, reqParam, clazz, new Listener<T>() {
                @Override
                public void onResponse(T response) {
                    if (response != null) {
                        if (cache) {
                            CacheConfig.methodExpireTimes.put(protocol, expireTime);
                            CacheManager.put(protocol, requestParamBody, response);
                        }
                    }
                    listener.onSuccess(response);
                }
            }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    if (BuildConfig.DEBUG) {
                        Log.e("AbsHttpRequestProxy", "error = " + error.toString());
                    }
                    listener.onFailed(error);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
        addRequestQueue();
    }

    /**
     * 加入请求队列
     */
    private void addRequestQueue() {
        RequestQueue requestQueue = HttpRequestManager.getInstance().getRequestQueue();
        if (!TextUtils.isEmpty(tag)) {
            request.setTag(tag);
        }
        Map<String, String> header = getHeader();
        if (header != null && header.size() > 0) {
            request.setHeaders(header);
        }
        request.setShouldCache(cache);
        request.setRetryPolicy(new DefaultRetryPolicy(
                DEFAULT_SOCKET_TIMEOUT_MS,
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        if (getCache) {
            Object response = CacheManager.get(protocol, requestParamBody);
            if (response != null) {
                listener.onSuccess((T) response);
                return;
            } else {
                requestQueue.add(request);
            }
        }
        requestQueue.add(request);
    }

    /**
     * 获取Json类型的请求参数
     */
    private String getRequestJsonString() {
        String jsonString = "";
        if (requestParamBody != null) {
            jsonString = mGson.toJson(requestParamBody);
            JSONObject jsonObject = null;
            try {
                jsonObject = new JSONObject(jsonString);
                TreeMap<String, String> commonParams = getCommonParamMap();
                if (commonParams != null) {
                    for (Map.Entry<String, String> entry : commonParams.entrySet()) {
                        jsonObject.put(entry.getKey(), entry.getValue());
                    }
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
            if (jsonObject != null) {
                jsonString = jsonObject.toString();
            }
            if (jsonString.equals("{}")) {
                jsonString = "";
            }
        }
        return jsonString;
    }

    /**
     * 获取Map格式请求参数
     */
    private TreeMap<String, String> getRequestParams() {
        TreeMap<String, String> filedMap = new TreeMap<>();
        // 反射publicFiled类的所有字段
        Class cla = requestParamBody.getClass();
        Method[] m = cla.getMethods();
        for (int i = 0; i < m.length; i++) {
            String method = m[i].getName();
            if (method.startsWith("get") && !method.contains("getClass")) {
                try {
                    Object value = m[i].invoke(requestParamBody);
                    if (value != null) {
                        String key = method.substring(3);
                        key = key.substring(0, 1).toLowerCase() + key.substring(1);
                        filedMap.put(key, value + "");
                    }
                } catch (Exception e) {
                    System.out.println("error:" + method);
                }
            }
        }
        return filedMap;
    }

    /**
     * 构造Post请求Url
     *
     * @param protocol 协议名
     */
    private String buildRequestUrl(String protocol) {
        if (TextUtils.isEmpty(protocol)) {
            throw new IllegalArgumentException("argument protocol can not be null");
        }
        if (protocol.contains("http://") || protocol.contains("https://")) {
            return protocol;
        }
        return getDomain() + protocol;
    }

}
